#if UNITY_EDITOR && DEBUG_BEHAVIOUR_TREE
#define DEBUG_TREE
#endif
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace GameToolkit.BehaviourTree
{
    // 实现该接口的装饰组件将不在 inspector 窗口展示属性列表
    public interface IWithoutInspectorComposite { }

    internal enum ConditionLogic
    {
        And,
        Or,
    }

    /// <summary>
    /// 组合节点输入/输出状态
    /// </summary>
    [System.Serializable]
    internal struct CompositeState
    {
        [SerializeReference]
        public Composite composite;

        [SerializeField]
        public NodeState state;

        public CompositeState(Composite composite, NodeState state)
        {
            this.composite = composite;
            this.state = state;
        }
    }

    internal sealed class NotLogicInput : Decoration, IInterruptionSource, IWrapCallback
    {
        BehaviourTreeObject mWrapInstance;
        internal IInterruptionSource mInput;
        public BehaviourTreeObject wrapInstance => mWrapInstance;

        internal NotLogicInput(BehaviourTreeObject input)
        {
            mWrapInstance = input;
            mInput = input as IInterruptionSource;
        }

        protected override void OnCreate(BehaviourTreePlayer player)
        {
        }

        protected override void OnDestroy(BehaviourTreePlayer player)
        {
        }

        NodeState IInterruptionSource.GetInterruptResult(BehaviourTreePlayer player)
        {
            return mInput == null ? NodeState.Running : mInput.GetNotInterruptResult(player);
        }

        NodeState IInterruptionSource.GetNotInterruptResult(BehaviourTreePlayer player)
        {
            return mInput == null ? NodeState.Failed : mInput.GetInterruptResult(player);
        }

        internal override void InitializeSelf(CreateBehaviourTreeContext context)
        {
            base.InitializeSelf(context);
            mWrapInstance?.InitializeSelf(context);
        }

        internal override void InvokeCreateRecursive(BehaviourTreePlayer player)
        {
            mWrapInstance?.InvokeCreateRecursive(player);
        }

        internal override void InvokeDestroyRecursive(BehaviourTreePlayer player)
        {
            mWrapInstance?.InvokeDestroyRecursive(player);
        }
        internal override void GetRootCallbacks(ICollection<IExecutableRootCallback> callbacks)
        {
            mWrapInstance?.GetRootCallbacks(callbacks);
        }
    }

    internal abstract class ComplexLogicInput : Decoration, IInterruptionSource
    {
        protected IInterruptionSource[] mInputs;
        internal abstract ConditionLogic Logic { get; }
#if UNITY_EDITOR
        internal override void InternalReplace(BehaviourTreeObject other)
        {
            base.InternalReplace(other);
            if (other is ComplexLogicInput cinput)
            {
                mInputs = cinput.mInputs;
            }
        }
#endif

        protected override void OnCreate(BehaviourTreePlayer player)
        {
        }

        protected override void OnDestroy(BehaviourTreePlayer player)
        {
        }

        internal override void InitializeSelf(CreateBehaviourTreeContext context)
        {
            base.InitializeSelf(context);
            mInputs = context.interruptionBuffer.ToArray();
        }
        internal override void GetRootCallbacks(ICollection<IExecutableRootCallback> callbacks)
        {
            var len = mInputs == null ? 0 : mInputs.Length;
            for (int i = 0; i < len; i++)
            {
                ((BehaviourTreeObject)mInputs[i]).GetRootCallbacks(callbacks);
            }
        }
        internal override void InvokeCreateRecursive(BehaviourTreePlayer player)
        {
            var len = mInputs == null ? 0 : mInputs.Length;
            for (int i = 0; i < len; i++)
            {
                ((BehaviourTreeObject)mInputs[i]).InvokeCreateRecursive(player);
            }
            base.InvokeCreateRecursive(player);
        }

        internal override void InvokeDestroyRecursive(BehaviourTreePlayer player)
        {
            base.InvokeDestroyRecursive(player);
            var len = mInputs == null ? 0 : mInputs.Length;
            for (int i = 0; i < len; i++)
            {
                ((BehaviourTreeObject)mInputs[i]).InvokeDestroyRecursive(player);
            }
        }
        public abstract NodeState GetInterruptResult(BehaviourTreePlayer player);
        public abstract NodeState GetNotInterruptResult(BehaviourTreePlayer player);
    }

    internal sealed class AndLogicInput : ComplexLogicInput
    {
        internal AndLogicInput() { }

        internal override ConditionLogic Logic => ConditionLogic.And;

        internal AndLogicInput(IInterruptionSource[] inputs)
        {
            mInputs = inputs;
        }

        public override NodeState GetInterruptResult(BehaviourTreePlayer player)
        {
            var result = NodeState.Running;
            var len = mInputs == null ? 0 : mInputs.Length;
            for (int i = 0; result == NodeState.Running && i < len; i++)
            {
                var decor = mInputs[i];
                result = decor.GetInterruptResult(player);
#if DEBUG_TREE
                ((Decoration)decor).State = result;
#endif
            }
            return result;
        }

        public override NodeState GetNotInterruptResult(BehaviourTreePlayer player)
        {
            var len = mInputs == null ? 0 : mInputs.Length;
            var result = NodeState.Failed;
            for (int i = 0; result != NodeState.Running && i < len; i++)
            {
                var decor = mInputs[i];
                var stat = decor.GetNotInterruptResult(player);
                if (stat == NodeState.Running || result != NodeState.Success)
                    result = stat;
#if DEBUG_TREE
                ((Decoration)decor).State = stat;
#endif
            }
            return result;
        }
    }

    internal sealed class OrLogicInput : ComplexLogicInput
    {
        internal OrLogicInput() { }
        internal override ConditionLogic Logic => ConditionLogic.Or;

        internal OrLogicInput(IInterruptionSource[] inputs)
        {
            mInputs = inputs;
        }

        public override NodeState GetInterruptResult(BehaviourTreePlayer player)
        {
            var len = mInputs == null ? 0 : mInputs.Length;
            var result = len == 0 ? NodeState.Running : NodeState.Failed;
            for (int i = 0; result != NodeState.Running && i < len; i++)
            {
                var decor = mInputs[i];
                var stat = decor.GetInterruptResult(player);
                if (stat == NodeState.Running || result != NodeState.Success)
                    result = stat;
#if DEBUG_TREE
                ((Decoration)decor).State = stat;
#endif
            }
            return result;
        }

        public override NodeState GetNotInterruptResult(BehaviourTreePlayer player)
        {
            var len = mInputs == null ? 0 : mInputs.Length;
            var result = len == 0 ? NodeState.Failed : NodeState.Running;
            for (int i = 0; result == NodeState.Running && i < len; i++)
            {
                var decor = mInputs[i];
                result = decor.GetNotInterruptResult(player);
#if DEBUG_TREE
                ((Decoration)decor).State = result;
#endif
            }
            return result;
        }
    }

    /// <summary>
    /// 组合逻辑节点
    /// </summary>
    internal abstract class LogicWithInputComposite : Composite
    {
        internal abstract bool IsMultiInput { get; }
        internal abstract CompositeState[] inputs { get; set; }
        internal virtual string InputPortName => "Input(s)";
    }

    internal abstract class LogicCombinationComposite : LogicWithInputComposite, IWithoutInspectorComposite
    {
        [SerializeField, HideInInspector, JsonCloneable(false)]
        internal CompositeState[] m_Inputs;
        internal override CompositeState[] inputs
        {
            get
            {
                return m_Inputs;
            }
            set
            {
                m_Inputs = value == null ? new CompositeState[0] : value;
            }
        }

        internal override bool IsMultiInput => true;

#if UNITY_EDITOR
        internal override void ResetGUID()
        {
            base.ResetGUID();
            var len = m_Inputs == null ? 0 : m_Inputs.Length;
            for (int i = 0; i < len; i++)
            {
                m_Inputs[i].composite?.ResetGUID();
            }
        }
#endif
    }

    [System.Serializable]
    [CompositeTitle("条件与")]
    [CompositeIcon("baad7c299c663c946908f82e6a925719")]
    [CompositeCategory]
    internal sealed class AndComposite : LogicCombinationComposite
    {
        internal override string InputPortName => "AND";
        public override string GetDescription()
        {
            var len = inputs == null ? 0 : inputs.Length;
            return $"组合方式： 与";
        }
        public override BehaviourTreeObject Create()
        {
            return new AndLogicInput();
        }
    }


    [System.Serializable]
    [CompositeTitle("条件或")]
    [CompositeIcon("0e8ec6657914e714196e16340921a10f")]
    [CompositeCategory]
    internal sealed class OrComposite : LogicCombinationComposite
    {
        internal override string InputPortName => "OR";
        public override string GetDescription()
        {
            var len = inputs == null ? 0 : inputs.Length;
            return $"组合方式： 或";
        }
        public override BehaviourTreeObject Create()
        {
            return new OrLogicInput();
        }
    }


}
